package com.unytech.project.web.action.security;

import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;

import com.opensymphony.xwork2.Action;
import com.unytech.project.annotation.ActionMethodLabel;
import com.unytech.project.annotation.enumerate.CallWay;
import com.unytech.project.annotation.enumerate.InterceptLevel;
import com.unytech.project.annotation.enumerate.LogRecordLevel;
import com.unytech.project.common.Globals;
import com.unytech.project.common.enumerate.LoginControl;
import com.unytech.project.entity.security.LoginRecord;
import com.unytech.project.entity.system.Permission;
import com.unytech.project.entity.system.User;
import com.unytech.project.service.security.LoginRecordService;
import com.unytech.project.service.system.PermissionService;
import com.unytech.project.service.system.UserService;
import com.unytech.project.web.action.BaseAction;

public class LoginAction extends BaseAction {
	private String username;    //记录用户名
	private String password;    //记录密码，不需回显，无get方法
	private String verifycode;  //记录验证码，不需回显，无get方法
		
	@Resource private UserService userService;  
	@Resource private PermissionService permissionService;
	@Resource private LoginRecordService loginRecordService;
	
	@ActionMethodLabel(intercept=InterceptLevel.INITSYSTEM, methodnote="用户登录")
	public String userLogin() throws Exception{		
		String verifycodeinsession = (String) getSession().getAttribute(Globals.SESSION_VERIFYCODE_KEY);
		if (verifycodeinsession == null || verifycodeinsession.trim().equals("") || !verifycodeinsession.equals(this.verifycode))
		{	
			addActionMessage("验证码错误！");
			return Action.LOGIN;
		}			
		if (this.username == null || this.username.trim().equals("") || this.password == null || this.password.trim().equals(""))
		{	
			addActionMessage("用户名或密码不能为空！");
			return Action.LOGIN;
		}
			
		User loginuser = null;
		try {
			loginuser = userService.loginVerify(this.username, this.password);
		} catch (Exception e) {
			logger.info(e.getMessage());
		}
		
		if (loginuser == null)
		{
			addActionMessage("用户名或密码错误！");
			return Action.LOGIN;
		}
		
		if (loginuser.getState() == 0)
		{
			addActionMessage("此账户已被冻结，请联系管理员！");
			return Action.LOGIN;
		}
		
		System.out.println("getRequestURL:"+getRequest().getRequestURL());
		System.out.println("getRequestURI:"+getRequest().getRequestURI());
		System.out.println("getRemoteAddr:"+getRequest().getRemoteAddr());
		System.out.println("getRemoteHost:"+getRequest().getRemoteHost());
		System.out.println("getRemotePort:"+getRequest().getRemotePort());
		System.out.println("getRemoteUser:"+getRequest().getRemoteUser());
		
		System.out.println("getHeader-Referer:"+getRequest().getHeader("Referer"));
		System.out.println("getHeader-Agent:"+getRequest().getHeader("User-Agent"));
		System.out.println("getHeader-x-forwarded-for:"+getRequest().getHeader("x-forwarded-for"));
		System.out.println("getHeader-Proxy-Client-IP:"+getRequest().getHeader("Proxy-Client-IP"));
		System.out.println("getHeader-WL-Proxy-Client-IP:"+getRequest().getHeader("WL-Proxy-Client-IP"));
		System.out.println("getHeaderNames:"+getRequest().getHeaderNames());
		
		System.out.println("getLocalAddr:"+getRequest().getLocalAddr());
		System.out.println("getLocalName:"+getRequest().getLocalName());
		System.out.println("getLocalPort:"+getRequest().getLocalPort());
		System.out.println("getMethod:"+getRequest().getMethod());
		
		System.out.println("getPathInfo:"+getRequest().getPathInfo());
		System.out.println("getLocale:"+getRequest().getLocale());
		
		
		//设置要添加到SESSION中去的用户的信息，考虑到内存占用所以除去从数据库中查询出来的用户的一部分不需要的信息
		User sessionuser = new User();
		sessionuser.setUserid(loginuser.getUserid());
		sessionuser.setUsername(loginuser.getUsername());
//		sessionuser.setRealname(loginuser.getRealname());
		sessionuser.setState(loginuser.getState());
		sessionuser.setDelor(loginuser.getDelor());
		sessionuser.setLoginip(getRequest().getRemoteAddr());
		sessionuser.setLogintime(new Date());
		
		//以下代码是用户登录控制
		LoginRecord loginrecord = new LoginRecord();
		
		//这里用Hashtable是因为线程安全，LinkHashTable可以实现顺序但是线程不安全不能在listener中使用
		/**key的值是“User的ID+Session的ID”，对应的value是当前Session对象而不是User对象*/
		Hashtable<String, HttpSession> contextsessions = (Hashtable<String, HttpSession>) getServletContext().getAttribute(Globals.CONTEXT_ALLSESSIONS_KEY);
		if (contextsessions != null) {    
			if (contextsessions.size() < Integer.parseInt(systemParams.getContextmaxuser())) {
				for(Iterator<Entry<String, HttpSession>> ite = contextsessions.entrySet().iterator(); ite.hasNext();){   
					Map.Entry<String, HttpSession> entry = (Map.Entry<String, HttpSession>) ite.next();   
					String tempsessionkey = entry.getKey();   
					HttpSession tempsession = entry.getValue();
					User tempuser = (User) tempsession.getAttribute(Globals.SESSION_USERINSESSION_KEY);  
					  
					//第一，如果系统配置为帐户本地登录则注销所有异地会话，则销毁异地会话，创建本地会话，并更新全局变量中的会话信息
					if (loginuser.getUserid().equals(tempuser.getUserid()) && systemParams.getSessioncontrol().equals(LoginControl.LOGOUTOTHERSESSIONS.toString().toLowerCase())) {			
						//不完美的写法，因为这个方法将要被废除，考虑用其他方法实现，以代替预废除的方法
						//sbe.getSession().getSessionContext().getSession(tempsessionkey).invalidate();
						tempsession.invalidate();
						//考虑这一步是不是要做，因为注销一个Session之后会被SessionAttributeRemoved监听到，全局变量的移除工作也将会在那里处理
						contextsessions.remove(tempuser.getUserid()+"_"+tempsessionkey);
						//在全局变量中添加当前登录用户所创建的SESSION
						contextsessions.put(loginuser.getUserid()+"_"+getSession().getId(), getSession());
						loginRecordService.save(loginrecord);
					}
					
					//第二，如果系统配置为帐户已经登录则不允许再次登录，禁止本地登录，清空本地会话信息
					if (loginuser.getUsername().equals(tempuser.getUsername()) && systemParams.getSessioncontrol().equals(LoginControl.UNENDABLENEWSESSION.toString().toLowerCase())) {		  
						addActionMessage("您的帐号已在别的地方登录，请先注销另一回话！");
						return LOGIN;
					}
					
					 //第三，如果系统配置为运行一个账户可以用多个异地会话，除去本地多浏览器登录重复写入contextsessions
					if (loginuser.getUsername().equals(tempuser.getUsername()) && systemParams.getSessioncontrol().equals(LoginControl.ENDABLEOTHERESSIONS.toString().toLowerCase())) {  
						//记录另一个SESSION
						contextsessions.put(loginuser.getUserid()+"_"+getSession().getId(), getSession());
						loginRecordService.save(loginrecord);
					}
				}
			}
			else
			{
				addActionMessage("在线用户超过最大限制，请联系系统管理员！");
				return LOGIN;
			}
		}
		else
		{    //全局变量为空，也就是说这个是第一个登录的用户	
			contextsessions = new Hashtable<>();
			contextsessions.put(loginuser.getUserid()+"_"+getSession().getId(), getSession());
			//这里有疑问
//			getServletContext().setAttribute(Globals.CONTEXT_ALLSESSIONS_KEY, contextsessions);
			
			getSession().setAttribute(Globals.SESSION_USERINSESSION_KEY, loginuser);    //写入用户SESSION
		}

//		getSession().setAttribute(Globals.SESSION_USERINSESSION_KEY, loginuser);    //写入用户SESSION

		//权限处理，如果是超级管理员则读取数据库中的所有权限
		List<Permission> permlist = null;
		if (loginuser.getUsername().equals(systemParams.getAdminname()) && loginuser.getPassword().equals(systemParams.getAdminpwd())) {
			permlist = (List<Permission>) getServletContext().getAttribute(Globals.CONTEXT_ALLPERMISSIONS_KEY);
			if (permlist == null) {
				try {
					permlist = permissionService.findAll();
				} catch (Exception e) {
					errorrecord.setErrordescribe("用户登录：查找数据库中全部权限时产生例外");
					getSession().setAttribute(Globals.SESSION_ERRORRECORD, errorrecord);
					throw e;
				}
			}
		}
		//从数据库中取出用户所拥有的权限
		try {
			permlist = userService.getUserPermission(loginuser);
		} catch (Exception e) {
			errorrecord.setErrordescribe("用户登录：查找数据库中用户的权限时产生例外");
			getSession().setAttribute(Globals.SESSION_ERRORRECORD, errorrecord);
		}
		//如果你没有设置好USER、PERMISSIONGROUP、和PERMISSION之间的关系则不能用这种方法
//		permlist = loginuser.getPermgroup().getPermissions();
		
		//判断权限是否为空
		if (permlist == null || permlist.size() == 0) {
			
			addActionMessage("您没有被分配任何权限，请联系管理员！");
			return LOGIN;
		}
		//把权限写入session
		getSession().setAttribute(Globals.SESSION_USERPERMISSION_KEY, permlist);
		
		//返回主菜单数据
		List<Permission> mainmenu = new ArrayList<Permission>();
		for (Permission perm : permlist) {
			if (perm.getParentid().equals(Globals.ROOTPERMISSIONID)) {
				mainmenu.add(perm);
			}
		}
		getRequest().setAttribute("mainmenu", mainmenu);
		getSession().removeAttribute(Globals.SESSION_VERIFYCODE_KEY);  //登录成功后清除验证码
		
		return LOGINOK_VIEW;	
	}

	@ActionMethodLabel(intercept=InterceptLevel.PUBLIC, methodnote="退出系统")
	public String userLogout() throws Exception{
		
//		Set<String> onlineusers = (Set<String>) getApplication().get(GlobalEnum.ONLINEUSERS.toString());
//		User user = (User) getSession().get(GlobalEnum.LOGINUSER.toString());
//		
//		if (onlineusers.contains(user))
//		{
//			onlineusers.remove(user);
//			getApplication().put(GlobalEnum.ONLINEUSERS.toString(), onlineusers);
//		}
	
//		getSession().remove(Globals.CURSESSIONUSER_KEY);
//		getSession().remove(Globals.PERMISSIONINSESSION);
//		getSession().remove(Globals.VERIFYCODE);
		getSession().invalidate();
		logger.info("退出系统！        时间："+new Date());
		
		return LOGIN;
	}

	@ActionMethodLabel(intercept=InterceptLevel.PROTECTED, callway=CallWay.AJAX, methodnote="获取用户客户端信息")
	public String userClientInfoAJAX() throws Exception{
		
		return null;
	}
	
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getPassword() {
		return password;
	}
	public void setVerifycode(String verifycode) {
		this.verifycode = verifycode;
	}
	public String getVerifycode() {
		return verifycode;
	}
}
